package com.yst.sqlbuilder;

import com.yst.lambda.TableFieldFunc;

import java.util.*;
import java.util.stream.Collectors;

public class SQLFieldIn<T> extends SQLFieldExp<T> implements ISQLFieldExpression<T> {

    public SQLFieldIn(IAliasExpression tableAlias, TableFieldFunc<T, ?> field) {
        super(tableAlias, field);
    }

    public SQLFieldIn(TableFieldFunc<T, ?> field, IAliasExpression tableAlias) {
        super(field, tableAlias);
    }

    private final List<?> values = new ArrayList<>();

    public SQLFieldIn<T> setValues(Collection values) {
        this.values.addAll(values);
        return this;
    }

    private final List<SQLParam> namedParam = new ArrayList<>();

    public <R> SQLFieldIn<T> setValues(SQLParam<R>... values) {
        namedParam.addAll(Arrays.asList(values));
        return this;
    }

    private ISQLSelect selectExpression;

    public SQLFieldIn<T> setSelect(ISQLSelect selectExpression) {
        this.selectExpression = selectExpression;
        return this;
    }

    @Override
    public String generateExpression(GenerateParam param) {
        if (!values.isEmpty()) {
            if (values.get(0) instanceof Number || values.get(0) instanceof Boolean) {
                return super.getRealField().concat(" ").concat(Symbol.IN.symbol)
                        .concat(" ").concat(String.format("(%s)", values.stream().map(Object::toString)
                                .collect(Collectors.joining(","))));
            } else if (values.get(0) instanceof IExpression) {
                return super.getRealField().concat(" ").concat(Symbol.IN.symbol)
                        .concat(" ").concat(String.format("(%s)",
                                values.stream().map((it) -> ((IExpression) it).generateExpression(param))
                                        .collect(Collectors.joining("','", "'", "'"))));
            } else {
                for (Object value : values) {
                    SQLSafe.getInstance().checkValue(value.toString());
                }
                return super.getRealField().concat(" ").concat(Symbol.IN.symbol)
                        .concat(" ").concat(String.format("(%s)",
                                values.stream().map(Object::toString)
                                        .collect(Collectors.joining("','", "'", "'"))));
            }
        } else if (!namedParam.isEmpty()) {
            return super.getRealField().concat(" ").concat(Symbol.IN.symbol)
                    .concat(" ").concat(String.format("(%s)",
                            namedParam.stream().map((it) -> it.generateExpression(param))
                                    .collect(Collectors.joining("','", "'", "'"))));
        } else if (Objects.nonNull(selectExpression)) {
            return super.getRealField().concat(" ").concat(Symbol.IN.symbol).concat(" ")
                    .concat(String.format("(%s)", selectExpression.generateExpression(param).trim()));
        } else {
            return "";
        }
    }
}
